#pragma once
#include <GLFW/glfw3.h>
#include <vulkan/vulkan_core.h>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>
#include <set>
#include <map>
#include "gfx-struct.h"
#include "gfx-object.h"
#include "gfx-shader.h"
#include "gfx-pass.h"
#include "gfx-pipeline.h"

class GfxMgr
{
private:
    GfxMgr(const GfxMgr &) = delete;            // 禁用拷贝构造
    GfxMgr &operator=(const GfxMgr &) = delete; // 禁用赋值操作符
    GfxMgr();
    ~GfxMgr();

    /**
     * @brief Vulkan实例句柄
     */
    VkInstance _vkinstance;
    void _createInstance();
    bool _checkValidationLayerSupport();
    std::vector<const char *> _getRequiredExtensions();
    void _populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT &createInfo);
    static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType,
                                                        const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData)
    {
        std::cerr << "Error Message: " << pCallbackData->pMessage << std::endl;
        return VK_FALSE;
    }
    VkDebugUtilsMessengerEXT _debugMessenger;
    void _setupDebugMessenger();
    VkResult _createDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pDebugMessenger);

    /**
     * @brief Vulkan表面句柄
     */
    VkSurfaceKHR _surface; // 用于显示的窗口句柄
    /**
     * @brief 创建Vulkan表面
     */
    void _createSurface();

    /**
     * @brief 物理设备句柄
     */
    VkPhysicalDevice _physicalDevice;
    /**
     * @brief 初始化物理设备
     */
    void _initPhysicalDevice();
    bool _isDeviceSuitable(VkPhysicalDevice device);
    bool _checkDeviceExtensionSupport(VkPhysicalDevice device);

    VkQueue _presentQueue; // 用来存储逻辑设备的图形呈现队列句柄
    VkQueue _graphicsQueue;
    /**
     * @brief 逻辑设备句柄
     */
    VkDevice _vkdevice;
    void _createLogicalDevice();

    /**
     * @brief 交换链
     * 本质上是一个等待被呈现在屏幕上的图像队列
     * 程序会在图像上进行绘制，然后再将其返回到队列中
     * Swap Chain的一般目的是使图像的呈现与屏幕的刷新率同步
     */
    VkSwapchainKHR _swapChain;
    std::vector<VkImage> _swapChainImages;
    VkFormat _swapChainImageFormat;
    VkExtent2D _swapChainExtent;
    void _createSwapChain();
    VkSurfaceFormatKHR _chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats);
    VkPresentModeKHR _chooseSwapPresentMode(const std::vector<VkPresentModeKHR> &availablePresentModes);
    VkExtent2D _chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities);

    /**
     * @brief 交换链图像视图
     * 为了在PipeLine中使用任何VkImage，包括Swap Chain中的那些Image，
     * 我们必须创建一个VkImageView对象。ImageView实际上是对图像的一种观察。
     * 它描述了如何访问图像以及访问图像的哪一部分，我们必须通过ImageView来能够读取Image
     */
    std::vector<VkImageView> _swapChainImageViews;
    void _createImageViews();

    VkCommandPool _commandPool;
    void _createCommandPool();

    /**
     * @brief 描述符池
     */
    VkDescriptorPool _descriptorPool;
    void _createDescriptorPool();

   

    

    // std::vector<VkBuffer> _uniformBuffers;
    // std::vector<VkDeviceMemory> _uniformBuffersMemory;
    // std::vector<void *> _uniformBuffersMapped;
    // void _createUniformBuffers();

    /**
     * 表示 交换链图像已经准备好可以被渲染。
     * vkAcquireNextImageKHR
     * 在 vkQueueSubmit() 中作为 等待条件（告诉 GPU："必须等图像准备好了才能开始渲染"）
     */
    std::vector<VkSemaphore> _imageAvailableSemaphores;
    /**
     * 表示 当前帧的渲染已经完成。
     * 由 vkQueueSubmit() 提交的命令执行完成后触发
     * 在 vkQueuePresentKHR() 中作为 等待条件（告诉 GPU："必须等渲染完成了才能显示"）
     */
    std::vector<VkSemaphore> _renderFinishedSemaphores;
    /**
     * 帧飞行栅栏
     * 表示 整个帧的 GPU 工作（提交的命令）是否完成。
     * vkQueueSubmit()
     * 通过 vkWaitForFences() 让 CPU 等待 GPU 完成工作
     * 通过 vkResetFences() 重置状态供下一帧使用
     */
    std::vector<VkFence> _inFlightFences;
    /**
     * 图像占用栅栏
     * 跟踪 每个交换链图像正在被哪一帧使用（防止多帧同时写同一图像
     * 数组大小 = 交换链图像数量
     * 当 vkAcquireNextImageKHR() 获取图像时，检查并关联当前帧的栅栏
     */
    std::vector<VkFence> _imagesInFlight;
    void _createSyncObjects();

    // 命令缓冲区操作
    VkCommandBuffer _beginSingleTimeCommands();
    void _endSingleTimeCommands(VkCommandBuffer commandBuffer);
    bool _hasStencilComponent(VkFormat format);

    size_t _currentFrame = 0;
    size_t _frameCount = 0;
    /**
     * 重置交换链
     */
    void _resetSwapChain();
    /**
     * @brief 第一个清除对象
     */
    GfxObject *_firstObject;
    /**
     * @brief 创建第一个清除对象
     */
    void _createFirstObject();
    std::map<std::string, GfxObject *> _uiObjects;
    std::map<std::string, GfxShader *> _shaders;
    std::map<std::string, GfxPass *> _passes;
    std::map<std::string, GfxPipeline *> _pipelines;
    std::map<std::string, GfxTexture *> _textures;

public:
    static GfxMgr *getInstance();

    /**
     * 初始化
     */
    void init();

    VkDevice getVulkanDevice();

    VkQueue getPresentQueue(); // 用来存储逻辑设备的图形呈现队列句柄
    VkQueue getGraphicsQueue();
    VkFormat getSwapChainImageFormat();
    VkExtent2D getSwapChainExtent();
    std::vector<VkImage> getSwapChainImages();
    std::vector<VkImageView> getSwapChainImageViews();
    VkCommandPool getCommandPool();
    VkDescriptorPool getDescriptorPool();

    void update(std::vector<std::string> &renderers);

    void createGfxTexture(std::string path,const void *pixels, int width, int height,int channels, int imageSize);
    void destroyGfxTexture(std::string path);


    // ui 节点渲染
    void addUIObject(std::string id);
    void updateUIObjectShader(std::string id, std::string shaderPath);
    void updateUIObjectVertexs(std::string id, std::vector<float> points, std::vector<float> colors, std::vector<float> normals, std::vector<float> uvs, std::vector<uint32_t> indices);
    void updateUIObjectColor(std::string id, float r, float g, float b, float a);
    void updateUIObjectTexture(std::string id, std::string texturePath);

    QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
    SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
    std::vector<char> readShaderFile(const std::string &filename);
    VkShaderModule createShaderModule(const std::vector<char> &code);
    VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkBuffer *buffer, VkDeviceMemory *memory, VkDeviceSize size, void *data);

    uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties);
    /**
     *  转换图像布局
     */
    void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels = 1);
    /**
     *  复制缓冲区到图像
     */
    void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height);
};